﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using Castle.Windsor;
using Castle.MicroKernel.Registration;
using System.IO;
using NHibernate.Metadata;
using NHibernate.Cfg;

namespace BeardCoder.Data.Framework.NHibernate.TestBase
{
    public class DevDbTestBase : IDbTestBase
    {
        public string NHibernateConfigFile { get; set; }
        public string[] MappingAssemblyDlls { get; set; }

        private ISessionFactory _sessionFactory;
        private WindsorContainer _container = new WindsorContainer();
        private Configuration _configuration;
        private static bool _wasInitialized = false;

        public DevDbTestBase(string nHibConfigFile, string[] mappingAssemblyDlls)
        {
            NHibernateConfigFile = nHibConfigFile;
            MappingAssemblyDlls = mappingAssemblyDlls;

            Initialize();
        }

        #region IDbTestBase

        public IRepository<T> ResolveRepository<T>()
        {
            return _container.Resolve<IRepository<T>>();
        }

        public TService ResolveService<TService>()
        {
            return _container.Resolve<TService>();
        }

        public ISession GetSession()
        {
            return _sessionFactory.GetCurrentSession();
        }

        public IDictionary<string, IClassMetadata> GetAllClassMetadata()
        {
            return _sessionFactory.GetAllClassMetadata();
        }

        public Configuration GetConfiguration()
        {
            return _configuration;
        }

        public void TearDown()
        {
            var session = LazySessionContext.UnBind(_sessionFactory);
            EndSession(session);
        }

        public void SetUp()
        {
            LazySessionContext.Bind(new Lazy<ISession>(() => BeginSession(_sessionFactory)), _sessionFactory);
        }

        #endregion

        #region Protected

        protected static ISession BeginSession(ISessionFactory sessionFactory)
        {
            var session = sessionFactory.OpenSession();
            session.BeginTransaction();
            return session;
        }

        protected void EndSession(ISession session)
        {
            try
            {
                if (session.Transaction != null && session.Transaction.IsActive)
                {
                    try
                    {
                        session.Transaction.Commit();
                    }
                    catch
                    {
                        session.Transaction.Rollback();
                        throw;
                    }
                }
            }
            finally
            {
                if (session.IsOpen)
                    session.Close();

                session.Dispose();
            }
        }

        protected virtual void Initialize()
        {
            if (!_wasInitialized)
            {
                var baseDir = AppDomain.CurrentDomain.BaseDirectory;
                var cfgFile = baseDir + "\\" + NHibernateConfigFile;
                var mappingAssemblies = from a in MappingAssemblyDlls select Path.Combine(baseDir, a);

                _configuration = Initializer.Initialize(cfgFile, mappingAssemblies.ToArray());
                _sessionFactory = _configuration.BuildSessionFactory();

                _container.Register(Component.For(typeof(IRepository<>))
                        .ImplementedBy(typeof(Repository<>))
                        .Named("repositoryType").LifeStyle.Transient);
                _container.Register(Component.For<ISessionFactory>()
                            .Instance(_sessionFactory).LifeStyle.Singleton);

                _wasInitialized = true;
            }
        }

        #endregion
    }
}
